package com.atguigu.tingshu.common.login;

import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.user.UserInfo;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @author atguigu-mqx
 * @ClassName GuiGuLoginAspect
 * @description: TODO
 * @date 2024年04月11日
 * @version: 1.0
 */
@Component
@Aspect
public class GuiGuLoginAspect {

    @Autowired
    private RedisTemplate redisTemplate;

    //  @annotation(org.springframework.transaction.annotation.Transactional)
    //  @Before("com.xyz.lib.Pointcuts.anyPublicMethod() && @annotation(auditable)")
    @Around("execution(* com.atguigu.tingshu.*.api.*.*(..)) && @annotation(guiGuLogin)")
    public Object loginAspect(ProceedingJoinPoint joinPoint, GuiGuLogin guiGuLogin) {
        //  判断是否需要登录，如果需要登录，必须有userId,如果没有，则抛出异常给页面，页面通过捕获异常弹出信息，提示用户必须登录.
        //  1. 如果用户登录成功了; 将用户信息存储到缓存中redis;  redis使用那种数据类型存储：
        //  String key=token value=userInfo.toString(); 做序列化操作。
        //  token存储到请求头中;
        //  从请求头中获取token，进而获取用户信息! 通过请求上下文对象来获取数据. SpringMVC 请求流程.
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
        //  获取到请求对象
        HttpServletRequest request = attributes.getRequest();
        //  获取到响应对象
        //  HttpServletResponse response = attributes.getResponse();

        //        HttpServletRequest httpServletRequest = (HttpServletRequest) requestAttributes;
        //        String t = httpServletRequest.getHeader("token");
        //        System.out.println("t:\t" + t);

        String token = request.getHeader("token");
        System.out.println("token:\t" + token);

        //  判断当前是否需要登录
        if (guiGuLogin.required()) {
            //  必须要登录
            if (StringUtils.isEmpty(token)) {
                //  抛出异常.
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
            //  组成redis key！
            String key = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
            //  从缓存中获取数据.
            UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(key);
            if (null == userInfo) {
                //  抛出异常.
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
        }

        //  不需要登录，后台微服务模块还想用到用户Id;
        if (!StringUtils.isEmpty(token)) {
            //  组成redis key！
            String key = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
            //  从缓存中获取数据.
            UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(key);
            if (null != userInfo) {
                //  将用户信息Id 存储到本地
                AuthContextHolder.setUserId(userInfo.getId());
                //  AuthContextHolder.setUsername(userInfo.getNickname());
            }
        }
        try {

            //  joinPoint.proceed(); 执行带有当前注解的方法体
            return joinPoint.proceed();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 删除用户Id
     */
    @After("execution(* com.atguigu.tingshu.*.api.*.*(..))")
    public void removeUserId() {
        //  删除用户信息
        AuthContextHolder.removeUserId();
    }
}
